﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;

namespace WindowsFormsApplication1
{
    public enum ContextType
    {
        MainContext,
        VHostContext
    }
    
    public enum ConfEntryType
    {
        ServerRoot, 
        User, 
        Group, 
        ServerAdmin, 
        ErrorLog, 
        LogLevel, 
        UserDir, 
        CheckSpelling, 
        Alias, 
        Listen, 
        ServerName, 
        NameVirtualHost, 
        DocumentRoot, 
        ServerAlias, 
        StringEntry, 
        VirtualHost, 
        VirtualHostClosure, 
        ConfFile,
        LoadModule
    }

    public enum LogLevels
    {
        warn = 0, 
        emerg, 
        alert, 
        crit, 
        error, 
        notice, 
        info, 
        debug
    }

    public partial class Form1 : Form
    {
        string mainConfigFilePath = "conf\\httpd.conf";
        string virtualServersPath = "conf\\virtuals.txt";
        string accessPath = "conf\\access.txt";
        List<string> namesOfVirtualHosts = new List<string>();
        List<string> currentVirtualHostsList;
        int defaultNumber = 0;

        ConfFile appConfFile = null;
        ServerRoot initialServerRoot = null;
        ConfFile mainConfFile = null;
        ConfFile virtualServersFile = null;
        List<IConfEntry> listOfVHosts = new List<IConfEntry>();
        ConfContext currentContext;

        public Form1()
        {
            InitializeComponent();

            Thread th = new Thread(new ThreadStart(DoSplash));
            th.Start();
            Thread.Sleep(2000);
            th.Abort();

            askForInitialServerRoot();
            initializeMainConfFile();
            initializeVirtualServersFile();
            initializeComponents();
            readMainConfigFile();
            checkForModules();
            updateContext();
        }

        private void DoSplash()
        {
            Splash sp = new Splash();
            sp.ShowDialog();
        }

        private void askForInitialServerRoot()
        {
            appConfFile = new ConfFile(".", "ZeroToServer.conf", false, true);
            appConfFile.readConfFile();
            appConfFile.parseFile();
            appConfFile.processFile();
            initialServerRoot = (ServerRoot)appConfFile.directives.Find(
                delegate(IConfEntry entry)
                {
                    return entry.EntryType == ConfEntryType.ServerRoot;
                }
            );
            if (initialServerRoot == null)
            {
                FolderBrowserDialog folderBrowse = new FolderBrowserDialog();
                folderBrowse.Description = "Wybierz ścieżkę ServerRoot:";
                if (folderBrowse.ShowDialog() == DialogResult.OK)
                {
                    initialServerRoot = new ServerRoot(folderBrowse.SelectedPath);
                    appConfFile.directives.Add(initialServerRoot);
                }
            }
            if (initialServerRoot == null)
            {
                // BLAD, tylko co tu z nim zrobic? zamknac aplikacje juz na etapie konstruktora? tymczasowo:
                initialServerRoot = new ServerRoot(".");
            }
        }

        private void initializeMainConfFile()
        {
            mainConfFile = new ConfFile(initialServerRoot.rootName, mainConfigFilePath, true, false);
            mainConfFile.readConfFile();
            mainConfFile.parseFile();
            mainConfFile.processFile();
        }

        private void initializeVirtualServersFile()
        {
            List<IConfEntry> includesList = ConfUtils.findAllByType(ConfEntryType.ConfFile, mainConfFile.directives);
            ConfFile pattern = new ConfFile(initialServerRoot.rootName, virtualServersPath, false, true);
            virtualServersFile = (ConfFile)includesList.Find(
                delegate(IConfEntry entry)
                {
                    return ((ConfFile)entry).Equals(pattern);
                }
            );
            if (virtualServersFile == null)
            {
                virtualServersFile = pattern;
                virtualServersFile.readConfFile();
                virtualServersFile.parseFile();
                virtualServersFile.processFile();
                mainConfFile.addFile(virtualServersFile);
            }
        }

        private void checkForModules()
        {
            bool modSpeling = false;
            bool modUserdir = false;
            bool modAlias = false;
            LoadModule newModule;
            MainContext mainCtx = MainContext.getInstance();
            List<IConfEntry> modulesList = mainCtx.LoadModules;
            foreach (IConfEntry entry in modulesList)
            {
                string entryCont = ((LoadModule)entry).entry;
                if (entryCont.Contains("mod_speling"))
                {
                    modSpeling = true;
                }
                else if (entryCont.Contains("mod_userdir"))
                {
                    modUserdir = true;
                }
                else if (entryCont.Contains("mod_alias"))
                {
                    modAlias = true;
                }
            }
            if (!modSpeling)
            {
                newModule = new LoadModule("speling_module modules/mod_speling.so");
                mainConfFile.addDirective(newModule);
                mainCtx.directs.Add(newModule);
            }
            if (!modUserdir)
            {
                newModule = new LoadModule("userdir_module modules/mod_userdir.so");
                mainConfFile.addDirective(newModule);
                mainCtx.directs.Add(newModule);
            }
            if (!modAlias)
            {
                newModule = new LoadModule("alias_module modules/mod_alias.so");
                mainConfFile.addDirective(newModule);
                mainCtx.directs.Add(newModule);
            }
        }

        private void initializeComponents()
        {
            contextCombo.DisplayMember = "Name";
            LogLevel_combo.DataSource = Enum.GetValues(typeof(LogLevels));
        }

        private void readMainConfigFile()
        {
            MainContext mainCtx = MainContext.getInstance();
            mainCtx.directs.AddRange(mainConfFile.getWholeTree());
            contextCombo.Items.Add(mainCtx);
            foreach (VirtualHost vHost in mainConfFile.virtualHosts)
            {
                contextCombo.Items.Add(vHost);
                listOfVHosts.Add(vHost);
            }
            contextCombo.SelectedItem = mainCtx;
        }

        private void updateContext()
        {
            readAlias();
            readVirtualServers();
            readConfig();
        }

        List<IConfEntry> listOfAliases;
        CheckSpelling chkSpell;
        UserDir usrDir;

        private void readAlias()
        {
            listOfAliases = currentContext.Aliases;
            dataGridView1.Rows.Clear();
            if (listOfAliases == null)
            {
                dataGridView1.Enabled = false;
            }
            else
            {
                dataGridView1.Enabled = true;
                foreach (IConfEntry entry in listOfAliases)
                {
                    Alias alias = (Alias)entry;
                    dataGridView1.Rows.Add(alias.AsRow);
                }
            }
            
            chkSpell = currentContext.CheckSpelling;
            if (chkSpell == null)
            {
                checkBox1.Checked = false;
            }
            else
            {
                checkBox1.Checked = chkSpell.enabled;
            }

            usrDir = currentContext.UserDir;
            if (usrDir == null)
            {
                usrDir = new UserDir();
                currentContext.directs.Add(usrDir);
                if (currentContext.CtxType == ContextType.MainContext)
                {
                    mainConfFile.addDirective(usrDir);
                }
                radioButton1.Checked = true;
            }
            else if (!String.IsNullOrWhiteSpace(usrDir.content))
            {
                if (String.Equals(usrDir.content, "public_html"))
                {
                    radioButton2.Checked = true;
                }
                else
                {
                    UserDirPath.Text = usrDir.content;
                    radioButton3.Checked = true;
                }
            }
            else
            {
                radioButton1.Checked = true;
            }

            /*radioButton1.Checked = true;

            DataGridViewComboBoxColumn typeColumn = new DataGridViewComboBoxColumn();
            typeColumn.Name = "Type";
            typeColumn.Items.AddRange("Alias", "AliasMatch", "Redirect", "RedirectMatch", "ScriptAlias", "ScriptAliasMatch");
            typeColumn.Width = 190;

            DataGridViewTextBoxColumn firstColumn = new DataGridViewTextBoxColumn();
            firstColumn.Name = "#1";
            firstColumn.Width = 190;

            DataGridViewTextBoxColumn secondColumn = new DataGridViewTextBoxColumn();
            secondColumn.Name = "#2";
            secondColumn.Width = 190;

            dataGridView1.Columns.Add(typeColumn);
            dataGridView1.Columns.Add(firstColumn);
            dataGridView1.Columns.Add(secondColumn);
           
            string line;
            System.IO.StreamReader fileReader = new System.IO.StreamReader(aliasPath);
            while ((line = fileReader.ReadLine()) != null)
            {
                string[] row = line.Split(' ');
                if (row[0] == "Alias" || row[0] == "AliasMatch" || 
                    row[0] == "ScriptAlias" || row[0] == "ScriptAliasMatch" || 
                    row[0] == "Redirect" || row[0] == "RedirectMatch")
                {
                    dataGridView1.Rows.Add(row);
                }
                else if (row[0] == "CheckSpelling")
                {
                    if (row[1] == "On")
                    {
                        checkBox1.Checked = false;
                    }
                    else
                    {
                        checkBox1.Checked = true;
                    }
                }
                else if (row[0] == "UserDir")
                {
                    radioButton3.Checked = true;
                    if (row[1] == "public_html")
                    {
                        radioButton2.Checked = true;
                    }
                    else
                    {
                        UserDirPath.Text = row[1];
                    }
                }
            }
            fileReader.Close();*/
        }

        List<VirtualHostEntry> listOfVHostEntries = new List<VirtualHostEntry>();

        private void readVirtualServers()
        {
            listOfVHostEntries.Clear();
            dataGridView2.Rows.Clear();
            foreach (IConfEntry entry in listOfVHosts)
            {
                VirtualHostEntry VHentry= new VirtualHostEntry((VirtualHost)entry);
                listOfVHostEntries.Add(VHentry);
                dataGridView2.Rows.Add(VHentry.AsRow);
            }

            /*string line;
            System.IO.StreamReader fileReader = new System.IO.StreamReader(virtualServersPath);
            bool inVirtualHostTag = false;
            string[] row = new string[4];
            char[] delimeter = { ' ', '\t', '>', '\n', '\r', '\"' };

            System.IO.File.Delete("log.txt");
            System.IO.StreamWriter fileWriter = new System.IO.StreamWriter("log.txt");

            while ((line = fileReader.ReadLine()) != null)
            {
                List<string> words = line.Split(delimeter, StringSplitOptions.None).ToList();

                for (int i = 0; i < words.Count(); i++)
                {
                    if (words[i].Length == 0)
                    {
                        words.RemoveAt(i);
                    }
                }

                foreach (string w in words)
                {
                    fileWriter.Write(' ' + w);
                }
                fileWriter.WriteLine();

                if (words.Count() == 0)
                {
                }
                else if (words[0] == "ServerName")
                {
                    if (!inVirtualHostTag)
                    {
                        //serverNameTextBox.Text = words[1];
                    }
                    else
                    {
                        if (words[1] == "default")
                        {
                            if (defaultNumber > 1)
                            {
                                // default moze byc tylko jeden
                                MessageBox.Show("Blad wczytywania pliku " + virtualServersPath + ": powtorzona nazwa \"default\".");
                                dataGridView2.Dispose();
                                break;
                            }
                            defaultNumber++;

                        }

                        row[1] = words[1];
                    }
                }
                else if (words[0] == "NameVirtualHost")
                {
                    namesOfVirtualHosts.Add(row[1]);
                }
                else if (words[0] == "<VirtualHost")
                {
                    row = new string[4];
                    currentVirtualHostsList = words.ToList();
                    currentVirtualHostsList.Remove("<VirtualHost");

                    // TODO: sprawdzenie, czy istnieje taki adres
                    inVirtualHostTag = true;
                }
                else if (words[0] == "DocumentRoot")
                {
                    if (!inVirtualHostTag)
                    {
                        MessageBox.Show("Blad wczytywania pliku " + virtualServersPath);
                        fileWriter.WriteLine("blad");
                        dataGridView2.Dispose();
                        break;
                    }
                    row[2] = words[1];
                }
                else if (words[0] == "ServerAlias")
                {
                    if (!inVirtualHostTag)
                    {
                        MessageBox.Show("Blad wczytywania pliku " + virtualServersPath);
                        fileWriter.WriteLine("blad");
                        dataGridView2.Dispose();
                        break;
                    }
                    row[3] = words[1];
                }
                else if (words[0] == "</VirtualHost")
                {
                    if (!inVirtualHostTag)
                    {
                        MessageBox.Show("Blad wczytywania pliku " + virtualServersPath);
                        fileWriter.WriteLine("blad");
                        dataGridView2.Dispose();
                        break;
                    }
                    inVirtualHostTag = false;
                    foreach (string w in currentVirtualHostsList)
                    {
                        row[0] = w;
                        dataGridView2.Rows.Add(row);
                    }
                }
            }
            fileReader.Close();
            fileWriter.Close();*/
        }

        ServerRoot serverRoot = null;
        User user = null;
        Group group = null;
        ServerAdmin serverAdmin = null;
        ServerName serverName = null;
        DocumentRoot documentRoot = null;
        ErrorLog errorLog = null;
        LogLevel logLevel = null;
        List<Listen> listOfListens = new List<Listen>();

        private void readConfig()
        {
            serverRoot = currentContext.ServerRoot;
            user = currentContext.User;
            group = currentContext.Group;
            serverAdmin = currentContext.ServerAdmin;
            serverName = currentContext.ServerName;
            documentRoot = currentContext.DocumentRoot;
            errorLog = currentContext.ErrorLog;
            logLevel = currentContext.LogLevel;

            if (currentContext.CtxType == ContextType.MainContext)
            {
                if (serverRoot == null)
                {
                    serverRoot = new ServerRoot();
                    serverRoot.SoftDeleted = true;
                    currentContext.directs.Add(serverRoot);
                    mainConfFile.addDirective(serverRoot);
                }
                if (user == null)
                {
                    user = new User();
                    user.SoftDeleted = true;
                    currentContext.directs.Add(user);
                    mainConfFile.addDirective(user);
                }
                if (group == null)
                {
                    group = new Group();
                    group.SoftDeleted = true;
                    currentContext.directs.Add(group);
                    mainConfFile.addDirective(group);
                }
                if (serverAdmin == null)
                {
                    serverAdmin = new ServerAdmin();
                    serverAdmin.SoftDeleted = true;
                    currentContext.directs.Add(serverAdmin);
                    mainConfFile.addDirective(serverAdmin);
                }
                if (serverName == null)
                {
                    serverName = new ServerName();
                    serverName.SoftDeleted = true;
                    currentContext.directs.Add(serverName);
                    mainConfFile.addDirective(serverName);
                }
                if (documentRoot == null)
                {
                    documentRoot = new DocumentRoot();
                    documentRoot.SoftDeleted = true;
                    currentContext.directs.Add(documentRoot);
                    mainConfFile.addDirective(documentRoot);
                }
                if (errorLog == null)
                {
                    errorLog = new ErrorLog();
                    errorLog.SoftDeleted = true;
                    currentContext.directs.Add(errorLog);
                    mainConfFile.addDirective(errorLog);
                }
                if (logLevel == null)
                {
                    logLevel = new LogLevel();
                    logLevel.SoftDeleted = true;
                    currentContext.directs.Add(logLevel);
                    mainConfFile.addDirective(logLevel);
                }
                List<IConfEntry> listOfListensEntries = currentContext.Listens;
                if (listOfListensEntries.Count > 0)
                {
                    listOfListens.Clear();
                    foreach (IConfEntry entry in listOfListensEntries)
                    {
                        listOfListens.Add((Listen)entry);
                    }
                }

                ServerRoot_text.Text = serverRoot.rootName;
                ServerRoot_text.Enabled = true;
                User_text.Text = user.userID;
                User_text.Enabled = true;
                Group_text.Text = group.groupID;
                Group_text.Enabled = true;
                if (String.IsNullOrWhiteSpace(serverAdmin.adminAddr))
                {
                    ServerAdminLogin_text.Text = null;
                    ServerAdminDomain_text.Text = null;
                }
                else
                {
                    string[] servAdm = serverAdmin.adminAddr.Split("@".ToCharArray(), 3, StringSplitOptions.None);
                    if (servAdm.Length != 2) {
                        // BLAD - niepoprawny adres e-mail
                    }
                    else
                    {
                        ServerAdminLogin_text.Text = servAdm[0];
                        ServerAdminDomain_text.Text = servAdm[1];
                    }
                }
                ServerAdminLogin_text.Enabled = true;
                ServerAdminDomain_text.Enabled = true;
                ServerName_text.Text = serverName.name;
                ServerName_text.Enabled = true;
                DocumentRoot_text.Text = documentRoot.path;
                DocumentRoot_text.Enabled = true;
                ErrorLog_text.Text = errorLog.logPath;
                ErrorLog_text.Enabled = true;
                LogLevel_combo.SelectedItem = logLevel.levelOfLogging;
                LogLevel_combo.Enabled = true;
                listenDataGridView.Rows.Clear();
                foreach (Listen listenEntry in listOfListens)
                {
                    listenDataGridView.Rows.Add(listenEntry.AsRow);
                }
                listenDataGridView.Enabled = true;
            }
            else
            {
                if (serverAdmin == null)
                {
                    serverAdmin = new ServerAdmin();
                    serverAdmin.SoftDeleted = true;
                    currentContext.directs.Add(serverAdmin);
                }
                if (serverName == null)
                {
                    serverName = new ServerName();
                    serverName.SoftDeleted = true;
                    currentContext.directs.Add(serverName);
                }
                if (documentRoot == null)
                {
                    documentRoot = new DocumentRoot();
                    documentRoot.SoftDeleted = true;
                    currentContext.directs.Add(documentRoot);
                }
                if (errorLog == null)
                {
                    errorLog = new ErrorLog();
                    errorLog.SoftDeleted = true;
                    currentContext.directs.Add(errorLog);
                }
                if (logLevel == null)
                {
                    logLevel = new LogLevel();
                    logLevel.SoftDeleted = true;
                    currentContext.directs.Add(logLevel);
                }
                
                ServerRoot_text.Text = null;
                ServerRoot_text.Enabled = false;
                User_text.Text = null;
                User_text.Enabled = false;
                Group_text.Text = null;
                Group_text.Enabled = false;
                if (String.IsNullOrWhiteSpace(serverAdmin.adminAddr))
                {
                    ServerAdminLogin_text.Text = null;
                    ServerAdminDomain_text.Text = null;
                }
                else
                {
                    string[] servAdm = serverAdmin.adminAddr.Split("@".ToCharArray(), 3, StringSplitOptions.None);
                    if (servAdm.Length != 2)
                    {
                        // BLAD - niepoprawny adres e-mail
                    }
                    else
                    {
                        ServerAdminLogin_text.Text = servAdm[0];
                        ServerAdminDomain_text.Text = servAdm[1];
                    }
                }
                ServerAdminLogin_text.Enabled = true;
                ServerAdminDomain_text.Enabled = true;
                ServerName_text.Text = serverName.name;
                ServerName_text.Enabled = true;
                DocumentRoot_text.Text = documentRoot.path;
                DocumentRoot_text.Enabled = true;
                ErrorLog_text.Text = errorLog.logPath;
                ErrorLog_text.Enabled = true;
                LogLevel_combo.SelectedItem = logLevel.levelOfLogging;
                LogLevel_combo.Enabled = true;
                listenDataGridView.Rows.Clear();
                listenDataGridView.Enabled = false;
            }


            /*string line;
            System.IO.StreamReader fileReader = new System.IO.StreamReader("httpd.conf");
            while ((line = fileReader.ReadLine()) != null)
            {
                line = line.Trim();
                if (!line.StartsWith("#"))
                {
                    int endOfLine = line.IndexOf('#');
                    if (endOfLine >= 0)
                    {
                        line = line.Remove(endOfLine);
                    }
                    string[] words = line.Split(" \t".ToCharArray(), 2, StringSplitOptions.RemoveEmptyEntries);
                    if (words.Length > 0)
                    {
                        if (words[0] == "ServerRoot")
                        {
                            if (words.Length > 1)
                            {
                                ServerRoot_text.Text = words[1];
                            }
                            else
                            {
                                // BLAD
                            }
                        }
                        else if (words[0] == "Listen")
                        {
                            if (words.Length > 1)
                            {
                                int portStart = words[1].LastIndexOf(':');
                                if (portStart >= 0)
                                {
                                    //ListenIP_text.Text = words[1].Substring(0, portStart);
                                   // ListenPort_text.Text = words[1].Substring(portStart + 1);
                                }
                                else
                                {
                                  //  ListenPort_text.Text = words[1];
                                }
                                if (words.Length > 2)
                                {
                                  //  ListenProtocol_text.Text = words[2];
                                }

                            }
                            else
                            {
                                // BLAD
                            }
                        }
                        else if (words[0] == "User")
                        {
                            if (words.Length > 1)
                            {
                                User_text.Text = words[1];
                            }
                            else
                            {
                                // BLAD
                            }
                        }
                        else if (words[0] == "Group")
                        {
                            if (words.Length > 1)
                            {
                                Group_text.Text = words[1];
                            }
                            else
                            {
                                // BLAD
                            }
                        }
                        else if (words[0] == "ServerAdmin")
                        {
                            if (words.Length > 1)
                            {
                                string[] addrParts = words[1].Split("@".ToCharArray());
                                if (addrParts.Length == 2 && addrParts[1].Contains("."))
                                {
                                    ServerAdminLogin_text.Text = addrParts[0];
                                    ServerAdminDomain_text.Text = addrParts[1];
                                }
                                else
                                {
                                    // BLAD
                                }
                            }
                            else
                            {
                                // BLAD
                            }
                        }
                        else if (words[0] == "ServerName")
                        {
                            if (words.Length > 1)
                            {
                                ServerName_text.Text = words[1];
                            }
                            else
                            {
                                // BLAD
                            }
                        }
                        else if (words[0] == "DocumentRoot")
                        {
                            if (words.Length > 1)
                            {
                                DocumentRoot_text.Text = words[1];
                            }
                            else
                            {
                                // BLAD
                            }
                        }
                        else if (words[0] == "ErrorLog")
                        {
                            if (words.Length > 1)
                            {
                                ErrorLog_text.Text = words[1];
                            }
                            else
                            {
                                // BLAD
                            }
                        }
                        else if (words[0] == "LogLevel")
                        {
                            if (words.Length > 1)
                            {
                                //LogLevel_combo.Text = words[1];
                                LogLevel_combo.SelectedItem = words[1];
                            }
                            else
                            {
                                // BLAD
                            }
                        }
                    }
                }
            }
            fileReader.Close();*/
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            string selection = (string)comboBox1.SelectedItem;
            foreach (DataGridViewRow row in dataGridView1.Rows)
            {
                if (row.IsNewRow == false)
                {
                    if (selection == "All")
                    {
                        row.Visible = true;
                    }
                    else
                    {
                        row.Visible = ((string)row.Cells[0].Value == selection);
                    }
                }
            }
        }

        private void createUsrDirIfNull()
        {
            if (usrDir == null)
            {
                usrDir = new UserDir();
                currentContext.directs.Add(usrDir);
                if (currentContext.CtxType == ContextType.MainContext)
                {
                    mainConfFile.addDirective(usrDir);
                }
            }
        }

        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            //createUsrDirIfNull();
            if (radioButton1.Checked)
            {
                UserDirPath.Enabled = false;
                usrDir.content = null;
            }
        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            //createUsrDirIfNull();
            if (radioButton2.Checked)
            {
                UserDirPath.Enabled = false;
                usrDir.content = "public_html";
            }
        }

        private void radioButton3_CheckedChanged(object sender, EventArgs e)
        {
            //createUsrDirIfNull();
            if (radioButton3.Checked)
            {
                UserDirPath.Enabled = true;
                usrDir.content = UserDirPath.Text;
            }
        }

        private void LogLevel_combo_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (logLevel == null)
            {
                return;
            }
            logLevel.levelOfLogging = (LogLevels)LogLevel_combo.SelectedItem;
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (tabControl1.SelectedTab.Equals(virtualHostsPage))
            {
                contextCombo.Enabled = false;
            }
            else
            {
                contextCombo.Enabled = true;
                if (tabControl1.SelectedTab.Equals(settingsTabPage))
                {
                    readConfig();
                }
            }
            updateContext();
        }

        private void contextCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            currentContext = (ConfContext)contextCombo.SelectedItem;
            updateContext();
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            mainConfFile.save();
            appConfFile.save();
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (chkSpell == null)
            {
                chkSpell = new CheckSpelling();
                currentContext.directs.Add(chkSpell);
                if (currentContext.CtxType == ContextType.MainContext)
                {
                    mainConfFile.addDirective(chkSpell);
                }
            }
            chkSpell.enabled = checkBox1.Checked;
        }

        private void UserDirPath_TextChanged(object sender, EventArgs e)
        {
            //if (!String.IsNullOrWhiteSpace(UserDirPath.Text))
            //{
            //    radioButton3.Checked = true;
            //}
            usrDir.content = UserDirPath.Text;
        }

        private Alias createAliasIfNew(int aliasIndex)
        {
            if (aliasIndex > listOfAliases.Count)
            {
                // BLAD
                return null;
            }
            else if (aliasIndex == listOfAliases.Count)
            {
                Alias newAlias = new Alias();
                listOfAliases.Add(newAlias);
                currentContext.directs.Add(newAlias);
                if (currentContext.CtxType == ContextType.MainContext)
                {
                    mainConfFile.addDirective(newAlias);
                }
            }
            return (Alias)listOfAliases[aliasIndex];
        }

        private void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
        {
            Alias changedAlias = createAliasIfNew(e.RowIndex);
            changedAlias.content[e.ColumnIndex] = (string)e.Value;
        }

        private void dataGridView1_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            int rowIndex = e.Row.Index;
            listOfAliases[rowIndex].Deleted = true;
            listOfAliases.RemoveAt(rowIndex);
        }

        private VirtualHostEntry createVHostIfNew(int vHostIndex)
        {
            if (vHostIndex > listOfVHostEntries.Count)
            {
                // BLAD
                return null;
            }
            else if (vHostIndex == listOfVHostEntries.Count)
            {
                VirtualHost newVHost = new VirtualHost();
                VirtualHostEntry newVHostEntry = new VirtualHostEntry(newVHost);
                listOfVHosts.Add(newVHost);
                contextCombo.Items.Add(newVHost);
                listOfVHostEntries.Add(newVHostEntry);
                virtualServersFile.addVHost(newVHost);
                MainContext.getInstance().directs.Add(newVHost);        // dangerous? rather not
            }
            return listOfVHostEntries[vHostIndex];
        }

        private void dataGridView2_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
        {
            VirtualHostEntry changedVHost = createVHostIfNew(e.RowIndex);
            switch (e.ColumnIndex)
            {
                case 0:
                    changedVHost.HostNames = (string)e.Value;
                    contextCombo.Items[e.RowIndex + 1] = changedVHost.vHost;
                    break;
                case 1:
                    changedVHost.ServerName = (string)e.Value;
                    contextCombo.Items[e.RowIndex + 1] = changedVHost.vHost;
                    break;
                case 2:
                    changedVHost.DocumentRoot = (string)e.Value;
                    break;
                case 3:
                    changedVHost.ServerAlias = (string)e.Value;
                    break;
            }
        }

        private void dataGridView2_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            int rowIndex = e.Row.Index;
            listOfVHostEntries.RemoveAt(rowIndex);
            contextCombo.Items.RemoveAt(rowIndex + 1);
            listOfVHosts[rowIndex].Deleted = true;
            listOfVHosts.RemoveAt(rowIndex);
        }

        private void ServerRoot_text_TextChanged(object sender, EventArgs e)
        {
            if (serverRoot == null)
            {
                return;
            }
            serverRoot.rootName = ServerRoot_text.Text;
            if (String.IsNullOrWhiteSpace(serverRoot.rootName))
            {
                serverRoot.SoftDeleted = true;
            }
            else
            {
                serverRoot.SoftDeleted = false;
            }
        }

        private void User_text_TextChanged(object sender, EventArgs e)
        {
            if (user == null)
            {
                return;
            }
            user.userID = User_text.Text;
            if (String.IsNullOrWhiteSpace(user.userID))
            {
                user.SoftDeleted = true;
            }
            else
            {
                user.SoftDeleted = false;
            }
        }

        private void Group_text_TextChanged(object sender, EventArgs e)
        {
            if (group == null)
            {
                return;
            }
            group.groupID = Group_text.Text;
            if (String.IsNullOrWhiteSpace(group.groupID))
            {
                group.SoftDeleted = true;
            }
            else
            {
                group.SoftDeleted = false;
            }
        }

        private void ServerAdminLogin_text_TextChanged(object sender, EventArgs e)
        {
            if (serverAdmin == null)
            {
                return;
            }
            serverAdmin.adminAddr = ServerAdminLogin_text.Text + "@" + ServerAdminDomain_text.Text;
            if (String.IsNullOrWhiteSpace(ServerAdminLogin_text.Text) || String.IsNullOrWhiteSpace(ServerAdminDomain_text.Text))
            {
                serverAdmin.SoftDeleted = true;
            }
            else
            {
                serverAdmin.SoftDeleted = false;
            }
        }

        private void ServerAdminDomain_text_TextChanged(object sender, EventArgs e)
        {
            if (serverAdmin == null)
            {
                return;
            }
            serverAdmin.adminAddr = ServerAdminLogin_text.Text + "@" + ServerAdminDomain_text.Text;
            if (String.IsNullOrWhiteSpace(ServerAdminLogin_text.Text) || String.IsNullOrWhiteSpace(ServerAdminDomain_text.Text))
            {
                serverAdmin.SoftDeleted = true;
            }
            else
            {
                serverAdmin.SoftDeleted = false;
            }
        }

        private void ServerName_text_TextChanged(object sender, EventArgs e)
        {
            if (serverName == null)
            {
                return;
            }
            serverName.name = ServerName_text.Text;
            if (String.IsNullOrWhiteSpace(serverName.name))
            {
                serverName.SoftDeleted = true;
            }
            else
            {
                serverName.SoftDeleted = false;
            }
        }

        private void DocumentRoot_text_TextChanged(object sender, EventArgs e)
        {
            if (documentRoot == null)
            {
                return;
            }
            documentRoot.path = DocumentRoot_text.Text;
            if (String.IsNullOrWhiteSpace(documentRoot.path))
            {
                documentRoot.SoftDeleted = true;
            }
            else
            {
                documentRoot.SoftDeleted = false;
            }
        }

        private void ErrorLog_text_TextChanged(object sender, EventArgs e)
        {
            if (errorLog == null)
            {
                return;
            }
            errorLog.logPath = ErrorLog_text.Text;
            if (String.IsNullOrWhiteSpace(errorLog.logPath))
            {
                errorLog.SoftDeleted = true;
            }
            else
            {
                errorLog.SoftDeleted = false;
            }
        }

        private Listen createListenIfNew(int listenIndex)
        {
            if (listenIndex > listOfListens.Count)
            {
                // BLAD
                return null;
            }
            else if (listenIndex == listOfListens.Count)
            {
                Listen newListen = new Listen();
                listOfListens.Add(newListen);
                currentContext.directs.Add(newListen);
                if (currentContext.CtxType == ContextType.MainContext)
                {
                    mainConfFile.addDirective(newListen);
                }
            }
            return listOfListens[listenIndex];
        }

        private void listenDataGridView_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
        {
            Listen changedListen = createListenIfNew(e.RowIndex);
            switch (e.ColumnIndex)
            {
                case 0:
                    changedListen.IPaddr = (string)e.Value;
                    break;
                case 1:
                    changedListen.PortNum = (string)e.Value;
                    break;
                case 2:
                    changedListen.ProtocolName = (string)e.Value;
                    break;
            }
        }

        private void listenDataGridView_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            int rowIndex = e.Row.Index;
            listOfListens[rowIndex].Deleted = true;
            listOfListens.RemoveAt(rowIndex);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (serverRoot == null) {
                // BLAD
            }
            string serverRootTrimmed = serverRoot.rootName.Trim(" \"\t".ToCharArray());
            if (serverRootTrimmed.IndexOfAny(System.IO.Path.GetInvalidPathChars()) != -1) {
                // BLAD
            }
            Process.Start(System.IO.Path.Combine(serverRootTrimmed, "bin\\httpd.exe"), "-k start");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (serverRoot == null)
            {
                // BLAD
            }
            string serverRootTrimmed = serverRoot.rootName.Trim(" \"\t".ToCharArray());
            if (serverRootTrimmed.IndexOfAny(System.IO.Path.GetInvalidPathChars()) != -1)
            {
                // BLAD
            }
            Process.Start(System.IO.Path.Combine(serverRootTrimmed, "bin\\httpd.exe"), "-k stop");
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (serverRoot == null)
            {
                // BLAD
            }
            string serverRootTrimmed = serverRoot.rootName.Trim(" \"\t".ToCharArray());
            if (serverRootTrimmed.IndexOfAny(System.IO.Path.GetInvalidPathChars()) != -1)
            {
                // BLAD
            }
            Process.Start(System.IO.Path.Combine(serverRootTrimmed, "bin\\httpd.exe"), "-k restart");
        }

        private void button4_Click(object sender, EventArgs e)
        {
            Donate sp = new Donate();
            sp.ShowDialog();
        }
    }

    abstract class ConfContext
    {
        public List<IConfEntry> directs;

        public abstract string Name
        {
            get;
        }

        public abstract ContextType CtxType
        {
            get;
        }

        public virtual List<IConfEntry> Directives
        {
            get
            {
                return directs;
            }
        }

        public virtual List<IConfEntry> VirtualHosts
        {
            get
            {
                return ConfUtils.findAllByType(ConfEntryType.VirtualHost, directs); //.Cast<VirtualHost>().ToList<VirtualHost>();
            }
        }

        public virtual ServerRoot ServerRoot
        {
            get
            {
                return (ServerRoot)ConfUtils.findByType(ConfEntryType.ServerRoot, directs);
            }
        }

        public virtual User User
        {
            get
            {
                return (User)ConfUtils.findByType(ConfEntryType.User, directs);
            }
        }

        public virtual Group Group
        {
            get
            {
                return (Group)ConfUtils.findByType(ConfEntryType.Group, directs);
            }
        }

        public virtual ServerAdmin ServerAdmin
        {
            get
            {
                return (ServerAdmin)ConfUtils.findByType(ConfEntryType.ServerAdmin, directs);
            }
        }

        public virtual ServerName ServerName
        {
            get
            {
                return (ServerName)ConfUtils.findByType(ConfEntryType.ServerName, directs);
            }
        }

        public virtual DocumentRoot DocumentRoot
        {
            get
            {
                return (DocumentRoot)ConfUtils.findByType(ConfEntryType.DocumentRoot, directs);
            }
        }

        public virtual ErrorLog ErrorLog
        {
            get
            {
                return (ErrorLog)ConfUtils.findByType(ConfEntryType.ErrorLog, directs);
            }
        }

        public virtual LogLevel LogLevel
        {
            get
            {
                return (LogLevel)ConfUtils.findByType(ConfEntryType.LogLevel, directs);
            }
        }

        public virtual List<IConfEntry> Listens
        {
            get
            {
                return ConfUtils.findAllByType(ConfEntryType.Listen, directs);
            }
        }

        public virtual List<IConfEntry> Aliases
        {
            get
            {
                return ConfUtils.findAllByType(ConfEntryType.Alias, directs);
            }
        }

        public virtual UserDir UserDir
        {
            get
            {
                return (UserDir)ConfUtils.findByType(ConfEntryType.UserDir, directs);
            }
        }

        public virtual CheckSpelling CheckSpelling
        {
            get
            {
                return (CheckSpelling)ConfUtils.findByType(ConfEntryType.CheckSpelling, directs);
            }
        }

        public virtual NameVirtualHost NameVirtualHost
        {
            get
            {
                return (NameVirtualHost)ConfUtils.findByType(ConfEntryType.NameVirtualHost, directs);
            }
        }

        public virtual ServerAlias ServerAlias
        {
            get
            {
                return (ServerAlias)ConfUtils.findByType(ConfEntryType.ServerAlias, directs);
            }
        }

        public virtual List<IConfEntry> LoadModules
        {
            get
            {
                return ConfUtils.findAllByType(ConfEntryType.LoadModule, directs);
            }
        }
    }

    interface IConfEntry
    {
        string Tag
        {
            get;
        }

        ConfEntryType EntryType
        {
            get;
        }

        bool Deleted
        {
            get;
            set;
        }

        bool SoftDeleted
        {
            get;
            set;
        }
    }

    class UserDir : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        private string cont;

        public UserDir() { }

        public UserDir(string content)
        {
            this.content = content;
        }

        public override string ToString()
        {
            return "UserDir " + content;
        }

        public string Tag
        {
            get
            {
                return "UserDir";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.UserDir;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }

        public string content
        {
            get
            {
                return cont;
            }
            set
            {
                cont = value;
                if (String.IsNullOrWhiteSpace(value))
                {
                    SoftDeleted = true;
                }
                else
                {
                    SoftDeleted = false;
                }
            }
        }
    }

    class CheckSpelling : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public bool enabled = false;

        public CheckSpelling() { }

        public CheckSpelling(bool enabled)
        {
            this.enabled = enabled;
        }

        public override string ToString()
        {
            if (enabled == true)
            {
                return "CheckSpelling On";
            }
            else
            {
                return "CheckSpelling Off";
            }
        }

        public string Tag
        {
            get
            {
                return "CheckSpelling";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.CheckSpelling;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class Alias : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string[] content = new string[3];

        public Alias() { }

        public Alias(string aliasType, string firstArg, string secondArg)
        {
            this.aliasType = aliasType;
            this.firstArg = firstArg;
            this.secondArg = secondArg;
        }

        public override string ToString()
        {
            return aliasType + " " + firstArg + " " + secondArg;
        }

        public string Tag
        {
            get
            {
                return "Alias";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.Alias;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }

        public string[] AsRow
        {
            get
            {
                return content;
            }
        }

        public string aliasType     // can have values Alias, AliasMatch, Redirect, RedirectMatch, ScriptAlias, ScriptAliasMatch
        {
            get
            {
                return content[0];
            }
            set
            {
                content[0] = value;
            }
        }
        public string firstArg
        {
            get
            {
                return content[1];
            }
            set
            {
                content[1] = value;
            }
        }
        public string secondArg
        {
            get
            {
                return content[2];
            }
            set
            {
                content[2] = value;
            }
        }
    }

    class Listen : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string[] content = new string[3];

        public Listen() { }

        public Listen(string IPaddr, string PortNum, string ProtocolName)
        {
            this.IPaddr = IPaddr;
            this.PortNum = PortNum;
            this.ProtocolName = ProtocolName;
        }

        public override string ToString()
        {
            return "Listen " + (String.IsNullOrWhiteSpace(IPaddr) ? "" : IPaddr + ":") + PortNum + (String.IsNullOrWhiteSpace(ProtocolName) ? "" : " "+ProtocolName);
        }

        public string Tag
        {
            get
            {
                return "Listen";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.Listen;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }

        public string IPaddr
        {
            get
            {
                return content[0];
            }
            set
            {
                content[0] = value;
            }
        }

        public string PortNum
        {
            get
            {
                return content[1];
            }
            set
            {
                content[1] = value;
                if (String.IsNullOrWhiteSpace(value))
                {
                    SoftDeleted = true;
                }
                else
                {
                    SoftDeleted = false;
                }
            }
        }

        public string ProtocolName
        {
            get
            {
                return content[2];
            }
            set
            {
                content[2] = value;
            }
        }

        public string[] AsRow
        {
            get
            {
                return content;
            }
        }
    }

    class ServerName : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string name;

        public ServerName() { }

        public ServerName(string name)
        {
            this.name = name;
        }

        public override string ToString()
        {
            return "ServerName "+name;
        }

        public string Tag
        {
            get
            {
                return "ServerName";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.ServerName;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class NameVirtualHost : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string address;

        public NameVirtualHost() { }

        public NameVirtualHost(string address)
        {
            this.address = address;
        }

        public override string ToString()
        {
            return "NameVirtualHost "+address;
        }

        public string Tag
        {
            get
            {
                return "NameVirtualHost";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.NameVirtualHost;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class DocumentRoot : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string path;

        public DocumentRoot() { }

        public DocumentRoot(string path)
        {
            this.path = path;
        }

        public override string ToString()
        {
            return "DocumentRoot " + path;
        }

        public string Tag
        {
            get
            {
                return "DocumentRoot";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.DocumentRoot;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class ServerAlias : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string path = null;

        public ServerAlias() { }

        public ServerAlias(string path)
        {
            this.path = path;
        }

        public override string ToString()
        {
            return "ServerAlias " + path;
        }

        public string Tag
        {
            get
            {
                return "ServerAlias";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.ServerAlias;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class StringEntry : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string entry;

        public StringEntry() { }

        public StringEntry(string entry)
        {
            this.entry = entry;
        }

        public override string ToString()
        {
            return entry;
        }

        public string Tag
        {
            get
            {
                return null;
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.StringEntry;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class ServerRoot : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string rootName;

        public ServerRoot() { }

        public ServerRoot(string rootName)
        {
            this.rootName = rootName;
        }

        public override string ToString()
        {
            return "ServerRoot " + rootName;
        }

        public string Tag
        {
            get
            {
                return "ServerRoot";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.ServerRoot;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class User : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string userID;

        public User() { }

        public User(string userID)
        {
            this.userID = userID;
        }

        public override string ToString()
        {
            return "User " + userID;
        }

        public string Tag
        {
            get
            {
                return "User";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.User;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class Group : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string groupID;

        public Group() { }

        public Group(string groupID)
        {
            this.groupID = groupID;
        }

        public override string ToString()
        {
            return "Group " + groupID;
        }

        public string Tag
        {
            get
            {
                return "Group";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.Group;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class ServerAdmin : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string adminAddr;

        public ServerAdmin() { }

        public ServerAdmin(string adminAddr)
        {
            this.adminAddr = adminAddr;
        }

        public override string ToString()
        {
            return "ServerAdmin " + adminAddr;
        }

        public string Tag
        {
            get
            {
                return "ServerAdmin";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.ServerAdmin;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class ErrorLog : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string logPath;

        public ErrorLog() { }

        public ErrorLog(string logPath)
        {
            this.logPath = logPath;
        }

        public override string ToString()
        {
            return "ErrorLog " + logPath;
        }

        public string Tag
        {
            get
            {
                return "ErrorLog";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.ErrorLog;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class LogLevel : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public LogLevels levelOfLogging;

        public LogLevel() { }

        public LogLevel(string loggingLevel)
        {
            this.levelOfLogging = (LogLevels)Enum.Parse(typeof(LogLevels), loggingLevel, true);
        }

        public override string ToString()
        {
            return "LogLevel " + levelOfLogging.ToString();
        }

        public string Tag
        {
            get
            {
                return "LogLevel";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.LogLevel;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class VirtualHost : ConfContext, IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string hostNames;

        public VirtualHost()
        {
            directs = new List<IConfEntry>();
        }

        public VirtualHost(string hostNames)
        {
            directs = new List<IConfEntry>();
            this.hostNames = hostNames;
        }

        public override string ToString()
        {

            StringBuilder sb = new StringBuilder();
            sb.Append("<VirtualHost ");
            sb.Append(hostNames);
            sb.AppendLine(">");
            foreach (IConfEntry entry in directs)
            {
                if (!entry.Deleted && !entry.SoftDeleted)
                {
                    sb.AppendLine(entry.ToString());
                }
            }
            sb.Append("</VirtualHost>");
            return sb.ToString();
        }

        public override string Name
        {
            get
            {
                StringBuilder sb = new StringBuilder();
                ServerName sName;
                sb.Append(hostNames);
                sName = this.ServerName;
                if (sName != null && !String.IsNullOrWhiteSpace(sName.name))
                {
                    sb.Append(" ");
                    sb.Append(sName.name);
                }
                return sb.ToString();
            }
        }

        public override ContextType CtxType
        {
            get
            {
                return ContextType.VHostContext;
            }
        }

        public override NameVirtualHost NameVirtualHost
        {
            get
            {
                return null;
            }
        }

        public override List<IConfEntry> VirtualHosts
        {
            get
            {
                return null;
            }
        }

        public override ServerRoot ServerRoot
        {
            get
            {
                return null;
            }
        }

        public override User User
        {
            get
            {
                return null;
            }
        }

        public override Group Group
        {
            get
            {
                return null;
            }
        }

        public override List<IConfEntry> Listens
        {
            get
            {
                return null;
            }
        }

        public string Tag
        {
            get
            {
                return "VirtualHost";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.VirtualHost;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class VirtualHostEntry
    {
        public VirtualHost vHost;
        public string[] content = new string[4];

        public VirtualHostEntry(VirtualHost vHost)
        {
            this.vHost = vHost;
            this.HostNames = HostNames;
            this.ServerName = ServerName;
            this.DocumentRoot = DocumentRoot;
            this.ServerAlias = ServerAlias;
        }

        public string[] AsRow
        {
            get
            {
                return content;
            }
        }
        public string HostNames
        {
            get
            {
                return vHost.hostNames;
            }
            set
            {
                if (String.IsNullOrWhiteSpace(value))
                {
                    vHost.Deleted = true;
                }
                else
                {
                    vHost.Deleted = false;
                }
                content[0] = value;
                vHost.hostNames = value;
            }
        }

        public string ServerName
        {
            get
            {
                return vHost.ServerName == null ? null : vHost.ServerName.name;
            }
            set
            {
                content[1] = value;
                if (vHost.ServerName != null)
                {
                    vHost.ServerName.name = value;
                }
                else
                {
                    vHost.directs.Add(new ServerName(value));
                }
                if (String.IsNullOrWhiteSpace(value))
                {
                    vHost.ServerName.SoftDeleted = true;
                }
                else
                {
                    vHost.ServerName.SoftDeleted = false;
                }
            }
        }

        public string DocumentRoot
        {
            get
            {
                return vHost.DocumentRoot == null ? null : vHost.DocumentRoot.path;
            }
            set
            {
                content[2] = value;
                if (vHost.DocumentRoot != null)
                {
                    vHost.DocumentRoot.path = value;
                }
                else
                {
                    vHost.directs.Add(new DocumentRoot(value));
                }
                if (String.IsNullOrWhiteSpace(value))
                {
                    vHost.DocumentRoot.SoftDeleted = true;
                }
                else
                {
                    vHost.DocumentRoot.SoftDeleted = false;
                }
            }
        }

        public string ServerAlias
        {
            get
            {
                return vHost.ServerAlias == null ? null : vHost.ServerAlias.path;
            }
            set
            {
                content[3] = value;
                if (vHost.ServerAlias != null)
                {
                    vHost.ServerAlias.path = value;
                }
                else
                {
                    vHost.directs.Add(new ServerAlias(value));
                }
                if (String.IsNullOrWhiteSpace(value))
                {
                    vHost.ServerAlias.SoftDeleted = true;
                }
                else
                {
                    vHost.ServerAlias.SoftDeleted = false;
                }
            }
        }
    }

    class VirtualHostClosure : IConfEntry
    {
        public string Tag
        {
            get
            {
                return "VirtualHostClosure";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.VirtualHostClosure;
            }
        }

        public bool Deleted
        {
            get { return true; }
            set { }
        }

        public bool SoftDeleted
        {
            get { return true; }
            set { }
        }
    }

    class LoadModule : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        public string entry;

        public LoadModule() { }

        public LoadModule(string entry)
        {
            this.entry = entry;
        }

        public override string ToString()
        {
            return "LoadModule " + entry;
        }

        public string Tag
        {
            get
            {
                return "LoadModule";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.LoadModule;
            }
        }

        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }
    }

    class MainContext : ConfContext
    {
        private static MainContext instance = null;

        private MainContext()
        {
            directs = new List<IConfEntry>();
        }

        public static MainContext getInstance()
        {
            if (instance == null)
            {
                instance = new MainContext();
            }
            return instance;
        }

        public override string Name
        {
            get
            {
                return "main-context";
            }
        }


        public override ContextType CtxType
        {
            get
            {
                return ContextType.MainContext;
            }
        }

        public override ServerAlias ServerAlias
        {
            get
            {
                return null;
            }
        }
    }

    static class ConfUtils
    {
        public static List<IConfEntry> findAllByTag(string tag, List<IConfEntry> directives)
        {
            return directives.FindAll(
                delegate(IConfEntry entry)
                {
                    return (!entry.Deleted && String.Equals(entry.Tag, tag, StringComparison.OrdinalIgnoreCase));
                }
            );
        }

        public static IConfEntry findByTag(string tag, List<IConfEntry> directives)
        {
            return directives.Find(
                delegate(IConfEntry entry)
                {
                    return (!entry.Deleted && String.Equals(entry.Tag, tag, StringComparison.OrdinalIgnoreCase));
                }
            );
        }

        public static List<IConfEntry> findAllByType(ConfEntryType type, List<IConfEntry> directives)
        {
            return directives.FindAll(
                delegate(IConfEntry entry)
                {
                    return (!entry.Deleted && entry.EntryType == type);
                }
            );
        }

        public static IConfEntry findByType(ConfEntryType type, List<IConfEntry> directives)
        {
            return directives.Find(
                delegate(IConfEntry entry)
                {
                    return (!entry.Deleted && entry.EntryType == type);
                }
            );
        }
    }

    class ConfFile : IConfEntry
    {
        public bool deleted = false;  // modify this field to indicate whether this entry should included in conf file
        public bool softDeleted = false;
        private bool rootFile;
        private bool overSoftDel;
        private bool inVHostTag = false;
        static char[] separators = " \t".ToCharArray();
        static char[] dirSeparators = { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar };
        bool wasRead = false;
        bool parsed = false;
        bool prepared = false;
        int lineNoParsing;
        private string serverRoot;
        private string relFile;
        private string file;
        public List<String> lines = new List<String>();
        public List<ConfFile> files = new List<ConfFile>();
        public List<IConfEntry> directives = new List<IConfEntry>();
        public List<IConfEntry> directAll = new List<IConfEntry>();     // dyrektywy z tego pliku i wszystkich zainkludowanych
        public List<VirtualHost> virtualHosts = null;

        public ConfFile(string serverRoot, string file, bool rootFile, bool overrideSoftDelete)
        {
            if (String.IsNullOrWhiteSpace(serverRoot))
            {
                // BLAD
                // serverRoot = @".";
            }
            if (String.IsNullOrWhiteSpace(file))
            {
                // BLAD
            }
            this.rootFile = rootFile;
            this.overSoftDel = overrideSoftDelete;
            virtualHosts = new List<VirtualHost>();
            serverRoot = serverRoot.Trim();
            file = file.Trim();
            file = file.TrimEnd(dirSeparators);
            this.serverRoot = serverRoot;
            this.relFile = file;
            if (!System.IO.Path.IsPathRooted(file))
            {
                file = System.IO.Path.Combine(serverRoot, file);
            }
            this.file = file.Replace(System.IO.Path.AltDirectorySeparatorChar, System.IO.Path.DirectorySeparatorChar);
        }

        public override bool Equals(object obj)
        {
            if (!obj.GetType().Equals(typeof(ConfFile)))
            {
                return false;
            }
            return file.Equals(((ConfFile)obj).file);
        }

        private bool insideBlock()
        {
            return inVHostTag;
        }

        private void copyBlockStatus(ConfFile targetFile)
        {
            targetFile.inVHostTag = inVHostTag;
        }

        private void readFile(string fileName)
        {
            string line;
            string lineHlp;
            // int lineNo = 0;
            System.IO.StreamReader fileReader = new System.IO.StreamReader(fileName);
            while ((line = fileReader.ReadLine()) != null)
            {
                // lineNo++;
                while (line.EndsWith(@"\"))
                {
                    lineHlp = fileReader.ReadLine();
                    if (lineHlp == null)
                    {
                        // BLAD??? - zadeklarowano dalszy ciag dyrektywy w nastepnej linii a to ju koniec pliku
                    }
                    else
                    {
                        line = line + lineHlp;
                    }
                    // lineNo++;
                }
                line = line.Trim();
                lines.Add(line);
            }
            fileReader.Close();
        }

        private void readDirectory(string dirName)
        {
            foreach (string entry in System.IO.Directory.GetFileSystemEntries(dirName)) {
                if (System.IO.File.Exists(entry))
                {
                    readFile(entry);
                }
                else if (System.IO.Directory.Exists(entry))
                {
                    readDirectory(entry);
                }
            }
        }

        public void readConfFile()
        {
            lines.Clear();
            if (System.IO.File.Exists(file))
            {
                readFile(file);
            }
            else if (System.IO.Directory.Exists(file))
            {
                readDirectory(file);
            }
            else
            {
                if (!System.IO.Directory.GetParent(file).Exists)
                {
                    System.IO.Directory.CreateDirectory(System.IO.Directory.GetParent(file).FullName);
                }
                System.IO.File.Create(file);
            }
            wasRead = true;
        }

        public void parseFile()
        {
            if (!wasRead)
            {
                return;
            }
            directAll.Clear();
            files.Clear();
            lineNoParsing = 0;
            IConfEntry entry;
            while ((entry = parseDirective()) != null)
            {
                switch (entry.EntryType)
                {
                    case ConfEntryType.ConfFile:
                        ConfFile fileEntry = (ConfFile)entry;
                        copyBlockStatus(fileEntry);
                        fileEntry.readConfFile();
                        fileEntry.parseFile();
                        if (insideBlock())
                        {
                            directAll.AddRange(fileEntry.directAll);
                        }
                        else
                        {
                            files.Add(fileEntry);
                            directAll.Add(entry);
                        }
                        break;
                    case ConfEntryType.VirtualHost:
                        inVHostTag = true;
                        directAll.Add(entry);
                        break;
                    case ConfEntryType.VirtualHostClosure:
                        inVHostTag = false;
                        directAll.Add(entry);
                        break;
                    default:
                        directAll.Add(entry);
                        break;
                }
            }
            parsed = true;
        }

        public void processFile()
        {
            if (!parsed)
            {
                return;
            }
            VirtualHost currVH = null;
            directives.Clear();
            virtualHosts.Clear();
            foreach (IConfEntry entry in directAll)
            {
                switch (entry.EntryType)
                {
                    case ConfEntryType.VirtualHost:
                        if (currVH != null)
                        {
                            // BLAD - dyrektywa <VirtualHost> zagniezdzona wewnatrz VirtualHosta
                        }
                        else
                        {
                            currVH = (VirtualHost)entry;
                        }
                        break;
                    case ConfEntryType.VirtualHostClosure:
                        if (currVH == null)
                        {
                            // BLAD - zamkniecie nieotwartego bloku <VirtualHost>
                        }
                        else
                        {
                            virtualHosts.Add(currVH);
                            directives.Add(currVH);
                            currVH = null;
                        }
                        break;
                    default:
                        if (currVH == null)
                        {
                            directives.Add(entry);
                        }
                        else
                        {
                            currVH.directs.Add(entry);
                        }
                        break;
                }
            }
            foreach (ConfFile subFile in files)
            {
                subFile.processFile();
                virtualHosts.AddRange(subFile.virtualHosts);
            }
            prepared = true;
        }

        public List<IConfEntry> getWholeTree()
        {
            if (!prepared)
            {
                return null;
            }
            List<IConfEntry> zwrot = new List<IConfEntry>();
            foreach (IConfEntry entry in directives)
            {
                if (entry.EntryType == ConfEntryType.ConfFile)
                {
                    zwrot.AddRange(((ConfFile)entry).getWholeTree());
                }
                else
                {
                    zwrot.Add(entry);
                }
            }
            return zwrot;
        }

        public IConfEntry parseDirective()
        {
            if (lineNoParsing >= lines.Count)
            {
                return null;
            }
            string line;
            string[] words;
            string[] wordsHlp;
            string[] wordsHlp2;
            line = lines[lineNoParsing];
            lineNoParsing++;
            if (String.IsNullOrEmpty(line) || line.StartsWith("#"))
            {
                return new StringEntry(line);
            }
            words = line.Split(separators, 2, StringSplitOptions.RemoveEmptyEntries);
            if (words[0].Equals("ServerRoot", StringComparison.OrdinalIgnoreCase))
            {
                return new ServerRoot(words[1]);
            }
            if (words[0].Equals("LoadModule", StringComparison.OrdinalIgnoreCase))
            {
                return new LoadModule(words[1]);
            }
            if (words[0].Equals("User", StringComparison.OrdinalIgnoreCase))
            {
                return new User(words[1]);
            }
            if (words[0].Equals("Group", StringComparison.OrdinalIgnoreCase))
            {
                return new Group(words[1]);
            }
            if (words[0].Equals("ServerAdmin", StringComparison.OrdinalIgnoreCase))
            {
                return new ServerAdmin(words[1]);
            }
            if (words[0].Equals("ErrorLog", StringComparison.OrdinalIgnoreCase))
            {
                return new ErrorLog(words[1]);
            }
            if (words[0].Equals("LogLevel", StringComparison.OrdinalIgnoreCase))
            {
                return new LogLevel(words[1]);
            }
            if (words[0].Equals("UserDir", StringComparison.OrdinalIgnoreCase))
            {
                return new UserDir(words[1]);
            }
            if (words[0].Equals("CheckSpelling", StringComparison.OrdinalIgnoreCase))
            {
                if (words[1].Equals("On", StringComparison.OrdinalIgnoreCase))
                {
                    return new CheckSpelling(true);
                }
                if (words[1].Equals("Off", StringComparison.OrdinalIgnoreCase))
                {
                    return new CheckSpelling(false);
                }
                return new StringEntry(line);
            }
            if (words[0].Equals("Alias", StringComparison.OrdinalIgnoreCase) ||
                words[0].Equals("AliasMatch", StringComparison.OrdinalIgnoreCase) ||
                words[0].Equals("Redirect", StringComparison.OrdinalIgnoreCase) ||
                words[0].Equals("RedirectMatch", StringComparison.OrdinalIgnoreCase) ||
                words[0].Equals("ScriptAlias", StringComparison.OrdinalIgnoreCase) ||
                words[0].Equals("ScriptAliasMatch", StringComparison.OrdinalIgnoreCase))
            {
                wordsHlp = words[1].Split(separators, 2, StringSplitOptions.RemoveEmptyEntries);
                return new Alias(words[0], wordsHlp[0], wordsHlp[1]);
            }
            if (words[0].Equals("Listen", StringComparison.OrdinalIgnoreCase))
            {
                string ip = null;
                string port = null;
                string protocol = null;
                wordsHlp = words[1].Split(separators, 2, StringSplitOptions.RemoveEmptyEntries);
                wordsHlp2 = wordsHlp[0].Split(":".ToCharArray(), 2, StringSplitOptions.RemoveEmptyEntries);
                if (wordsHlp.Length > 1)
                {
                    protocol = wordsHlp[1];
                }
                if (wordsHlp2.Length > 1)
                {
                    ip = wordsHlp2[0];
                    port = wordsHlp2[1];
                } else {
                    port = wordsHlp2[0];
                }
                return new Listen(ip, port, protocol);
            }
            if (words[0].Equals("ServerName", StringComparison.OrdinalIgnoreCase))
            {
                return new ServerName(words[1]);
            }
            if (words[0].Equals("NameVirtualHost", StringComparison.OrdinalIgnoreCase))
            {
                return new NameVirtualHost(words[1]);
            }
            if (words[0].Equals("DocumentRoot", StringComparison.OrdinalIgnoreCase))
            {
                return new DocumentRoot(words[1]);
            }
            if (words[0].Equals("ServerAlias", StringComparison.OrdinalIgnoreCase))
            {
                return new ServerAlias(words[1]);
            }
            if (words[0].Equals("<VirtualHost", StringComparison.OrdinalIgnoreCase))
            {
                int indexClosure = words[1].IndexOf('>');
                if (indexClosure < 0)
                {
                    // BLAD
                }
                //wordsHlp = words[1].Remove(indexClosure).Split(separators, StringSplitOptions.RemoveEmptyEntries);
                return new VirtualHost(words[1].Remove(indexClosure));
            }
            if (words[0].Equals("Include", StringComparison.OrdinalIgnoreCase))
            {
                return new ConfFile(serverRoot, words[1], false, false);
            }
            if (words[0].Equals("</VirtualHost>", StringComparison.OrdinalIgnoreCase) ||
                words[0].Equals("</VirtualHost", StringComparison.OrdinalIgnoreCase))
            {
                return new VirtualHostClosure();
            }

            return new StringEntry(line);
        }

        public void save()
        {
            if (deleted)
            {
                return;
            }
            if (!prepared)
            {
                // TO DO - komunikat?
                return;
            }
            foreach (ConfFile configFile in files)
            {
                configFile.save();
            }
            System.IO.StreamWriter writeFile = new System.IO.StreamWriter(file, false);
            writeFile.Write(getTotalString());
            writeFile.Close();
        }

        public void addFile(ConfFile subFile)
        {
            if (!prepared)
            {
                return;
            }
            // subFile.rootFile = false;
            if (!subFile.prepared)
            {
                subFile.processFile();
            }
            directives.Add(subFile);
            files.Add(subFile);
            virtualHosts.AddRange(subFile.virtualHosts);
        }

        public void addDirective(IConfEntry entry)
        {
            directAll.Add(entry);
            directives.Add(entry);
        }

        public void addVHost(VirtualHost vHost)
        {
            addDirective(vHost);
            virtualHosts.Add(vHost);
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Include ");
            if (relFile.Contains(' '))
            {
                sb.Append("\"");
                sb.Append(relFile);
                sb.Append("\"");
            }
            else
            {
                sb.Append(relFile);
            }
            return sb.ToString();
        }

        public string getTotalString()
        {
            StringBuilder sb = new StringBuilder();
            foreach (IConfEntry entry in directives)
            {
                if (!entry.Deleted && (!entry.SoftDeleted || overSoftDel))
                {
                    sb.AppendLine(entry.ToString());
                }
            }
            return sb.ToString();
        }

        public string Tag
        {
            get
            {
                return "Include";
            }
        }

        public ConfEntryType EntryType
        {
            get
            {
                return ConfEntryType.ConfFile;
            }
        }


        public bool Deleted
        {
            get { return deleted; }
            set { deleted = value; }
        }

        public bool SoftDeleted
        {
            get { return softDeleted; }
            set { softDeleted = value; }
        }

        public string File
        {
            get
            {
                return file;
            }
        }
    }
}
